// A simple authentication application written in HTML
// Copyright (C) 2012 Gerard Braad
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

(function(exports) {
	"use strict";

	var StorageService = function() {
		var setItem = function(key, value) {
			uni.setStorageSync(key, value)
		};

		var getItem = function(key) {
			return uni.getStorageSync(key)
		};

		return {
			getItem: getItem,
			setItem: setItem
		};
	};

	exports.StorageService = StorageService;

	// Originally based on the JavaScript implementation as provided by Russell Sayers on his Tin Isles blog:
	// http://blog.tinisles.com/2011/10/google-authenticator-one-time-password-algorithm-in-javascript/

	var KeyUtilities = function(jsSHA) {

		var dec2hex = function(s) {
			return (s < 15.5 ? '0' : '') + Math.round(s).toString(16);
		};

		var hex2dec = function(s) {
			return parseInt(s, 16);
		};

		var base32tohex = function(base32) {
			var base32chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
			var bits = "";
			var hex = "";

			for (var i = 0; i < base32.length; i++) {
				var val = base32chars.indexOf(base32.charAt(i).toUpperCase());
				bits += leftpad(val.toString(2), 5, '0');
			}

			for (i = 0; i + 4 <= bits.length; i += 4) {
				var chunk = bits.substr(i, 4);
				hex = hex + parseInt(chunk, 2).toString(16);
			}

			return hex;
		};

		var leftpad = function(str, len, pad) {
			if (len + 1 >= str.length) {
				str = new Array(len + 1 - str.length).join(pad) + str;
			}
			return str;
		};

		var generate = function(secret, epoch) {
			var key = base32tohex(secret);

			// HMAC generator requires secret key to have even number of nibbles
			if (key.length % 2 !== 0) {
				key += '0';
			}

			// If no time is given, set time as now
			if (typeof epoch === 'undefined') {
				epoch = Math.round(new Date().getTime() / 1000.0);
			}
			var time = leftpad(dec2hex(Math.floor(epoch / 30)), 16, '0');

			// external library for SHA functionality
			var hmacObj = new jsSHA(time, "HEX");
			var hmac = hmacObj.getHMAC(key, "HEX", "SHA-1", "HEX");

			var offset = 0;
			if (hmac !== 'KEY MUST BE IN BYTE INCREMENTS') {
				offset = hex2dec(hmac.substring(hmac.length - 1));
			}

			var otp = (hex2dec(hmac.substr(offset * 2, 8)) & hex2dec('7fffffff')) % 1000000 + '';
			return Array(7 - otp.length).join('0') + otp;
		};

		// exposed functions
		return {
			generate: generate
		};
	};

	exports.KeyUtilities = KeyUtilities;
})(typeof exports === 'undefined' ? this['gauth'] = {} : exports);